package dk.dashboardFP.panels.introspectionPanel {
	import dk.dashboardFP.interactionElementFramwork.buttons.ButtonEvent;
	import dk.dashboardFP.panels.ui.text.DFPAdvancedLabel;
	import dk.dashboardFP.panels.ui.text.DFPFonts;

	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;

	/**
	 * @author josef
	 */
	public class IntrospectionNodeView extends Sprite {
		private var _introspectionNode : IntrospectionNode;
		private var _nodeTextLabel : DFPAdvancedLabel;
		private var _bOpen : Boolean = false;
		private var _sprSubNodes : Sprite;
		private var _bSubNodesCreated : Boolean = false;
		private var _a_doINWs : Array;
		private var _doFoldButton : FoldButton;
		private var _width : Number;
		private var _subNodesOffsetX : Number = 15;
		private var _textHeight : Number = 0;
		private var _currentHeight : Number = 0;
		private var _isSearchHit : Boolean;
		private var _searchString : String;
		private var _isHidden : Boolean= false;

		public function IntrospectionNodeView(oIntrospectionNode : IntrospectionNode, parentWidth:Number=250) {
			_width = parentWidth - _subNodesOffsetX;
			_introspectionNode = oIntrospectionNode;
			_searchString = _introspectionNode.sValue.toLowerCase();
			
			setupElements();
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// setup
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		protected function setupElements() : void {

			//:::::::
			// label 

			if (_introspectionNode.sValue== "") {
				_introspectionNode.sValue="no value";
			}
 			
			_nodeTextLabel = new DFPAdvancedLabel(_introspectionNode.sValue, 10, 0xffffff, false, DFPFonts.REGULAR);
			_nodeTextLabel.nLeading=6;
			
			_nodeTextLabel.sHtmlText = _introspectionNode.sValue;
			
			addChild(_nodeTextLabel);
			
			_nodeTextLabel.makeMultiline();
			_nodeTextLabel.tfLabel.selectable=true;
			_nodeTextLabel.tfLabel.border=false;
			
			_nodeTextLabel.nWidth = _width;
			
			//:::::::
			// sub node button 
			
			if (_introspectionNode.a_oSubNodes) {
				
				_doFoldButton = new FoldButton();
				addChild(_doFoldButton);
				
				_doFoldButton.x = -11;
				_doFoldButton.y = 1;
				
				_doFoldButton.oController.addEventListener(ButtonEvent.CLICKED, onClick, false, 0, true);
			}
			
			if (_introspectionNode.a_oSubNodes) {
				if (_introspectionNode.depth<2) {
					openNode();
				}
			}
			
			addEventListener(MouseEvent.MOUSE_OVER, onOver, false, 0, true);
			addEventListener(MouseEvent.MOUSE_OUT, onOut);
			_nodeTextLabel.addEventListener(MouseEvent.CLICK, onLabelClick, false, 0, true);
		}

		protected function onLabelClick(event : MouseEvent) : void {
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// fold handlers
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		protected function onOut(event : MouseEvent) : void {
			event.stopImmediatePropagation();
			graphics.clear();
		}

		protected function onOver(event : MouseEvent) : void {
			
			graphics.beginFill(0xffffff, 0.08);
			graphics.drawRoundRect(-1, -1, width+2, nHeight+2, 6, 6);
			
			event.stopImmediatePropagation();
			
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// set width
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		public function setWidth(parentWidth:Number) : void {
			_width = parentWidth - 15;
			
			_nodeTextLabel.nWidth = _width;
			if (_nodeTextLabel.nHeight != _textHeight) {
				changeTextHeight();
				_textHeight = _nodeTextLabel.nHeight;
			}
			
			if (_bOpen) {
				updateSubNodesWidth();
			}
		}

		private function changeTextHeight() : void {
			if (_sprSubNodes) {
				_sprSubNodes.y = _nodeTextLabel.nHeight + ((_nodeTextLabel.tfLabel.numLines==1)?-5:2);
			}
			dispatchHeightChange();
		}

		private function updateSubNodesWidth() : void {
			if (_introspectionNode.a_oSubNodes) {
				for each (var subNodeView : IntrospectionNodeView in _a_doINWs) {
					subNodeView.setWidth(_width);
				}
			}
		}
		
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// create subnodes
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function createSubNodes() : void {
			
			//:::::::
			// prepare container 
			_sprSubNodes = new Sprite();
			addChild(_sprSubNodes);
			
			_sprSubNodes.y = _nodeTextLabel.nHeight + ((_nodeTextLabel.tfLabel.numLines==1)?-5:2);
			_sprSubNodes.x = _subNodesOffsetX;
			
			//:::::::
			// register 
			_sprSubNodes.addEventListener(IntrospectionNodeViewEvent.HEIGHT_CHANGED, onSubHeightChange, false, 0, true);
			
			//:::::::
			// loop 
			var intCount : int = 0;
			_a_doINWs = [];
			
			for each (var oIN : IntrospectionNode in _introspectionNode.a_oSubNodes) {
				
				var doINW : IntrospectionNodeView = getSubNode(oIN, _width);				
				_sprSubNodes.addChild(doINW);
				
				_a_doINWs[intCount] = doINW;
				intCount++;
			}
			
			placeSubNodes();
		}

		protected function getSubNode(oIN : IntrospectionNode, width : Number) : IntrospectionNodeView {
			return new IntrospectionNodeView(oIN, width);
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// place control
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function onSubHeightChange(event : Event) : void {
			placeSubNodes();
		}

		private function placeSubNodes() : void {
			
			var intCountY : Number = 0;
			for each (var doINW : IntrospectionNodeView in _a_doINWs) {
				if (!doINW.isHidden) {
					doINW.y = intCountY;
					intCountY += doINW.nHeight;
					if (!_sprSubNodes.contains(doINW)) {
						_sprSubNodes.addChild(doINW);
					} 
				} else {
					if (_sprSubNodes.contains(doINW)) {
						_sprSubNodes.removeChild(doINW);
					}
				}
			}
		}

		public function get nHeight() : Number {
			if (!_bOpen || _sprSubNodes.numChildren==0) {
				return _nodeTextLabel.nHeight + ((_nodeTextLabel.tfLabel.numLines==1)?-4:2);
			} else {
				return _sprSubNodes.y + _sprSubNodes.height + 5+ ((_nodeTextLabel.tfLabel.numLines==1)?-4:2);;
			}
		}
		
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// search
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		
		public function search(value : String) : void {
			
			_isSearchHit=false;
			
			//:::::::
			// search sub nodes
			var subNodeHit:Boolean=false; 
			
			if (!_sprSubNodes) {
				_bSubNodesCreated=true;
				createSubNodes();
			}
			
			for each (var subnode : IntrospectionNodeView in _a_doINWs) {
				
				subnode.search(value);
				if (subnode.isSearchHit) {
					_isSearchHit=true;
					subNodeHit=true;
				} 
			}
			
			if (subNodeHit) {
				openNode();
			} else {
				closeNode(true);
			}
			
			//:::::::
			// update subnodes  
			placeSubNodes();
			dispatchHeightChange();
			
			//:::::::
			// search self 
			if (_searchString.indexOf(value.toLowerCase())!= -1 || value=="") {
				_isSearchHit=true;
				_nodeTextLabel.alpha=1;
			} else {
				_nodeTextLabel.alpha=0.3;
			}
			
			if (!_isSearchHit) {
				_isHidden=true;
			} else {
				_isHidden=false;
			}
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// open close
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		protected function onClick(event : Event) : void {
			if (event is ButtonEvent) {
				toggleOpenClose(MouseEvent((event as ButtonEvent).oOriginalEvent).altKey);
			} else {
				toggleOpenClose((event as MouseEvent).altKey);
			}
		}

		private function toggleOpenClose(recursively:Boolean=false) : void {
			if (_bOpen) {
				closeNode(recursively);
			} else {
				openNode(recursively);
			}
		}

		public function openNode(openRecursively:Boolean=false) : void {
			
			if (_bOpen) return;
			
			//:::::::
			// show hidden sub nodes on open 
			for each (var doINW : IntrospectionNodeView in _a_doINWs) {
				if (doINW.isHidden) {
					doINW.isHidden=false;
				}
			}
			
			placeSubNodes();
			
			
			if (!_bSubNodesCreated) {
				_bSubNodesCreated = true;
				createSubNodes();
			}
			
			//:::::::
			// recursive open 
			if (openRecursively) {
				for each (var nodeView : IntrospectionNodeView in _a_doINWs) {
					if (nodeView.oIntrospectionNode.a_oSubNodes) {
						nodeView.openNode(true);
					}
				}
			}
			
			updateSubNodesWidth();
			
			_bOpen = true;
			addChild(_sprSubNodes);
			_doFoldButton.setOpen();

			dispatchHeightChange();
		}

		private function closeNode(closeRecursively:Boolean) : void {
			
			graphics.clear();
			
			if (!_bOpen) return;

			_bOpen = false;
			
			removeChild(_sprSubNodes);
			_doFoldButton.setClosed();
			
			//:::::::
			// recursive open 
			if (closeRecursively) {
				for each (var nodeView : IntrospectionNodeView in _a_doINWs) {
					if (nodeView.oIntrospectionNode.a_oSubNodes) {
						nodeView.closeNode(true);
					}
				}
			}
			
			dispatchHeightChange();
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// height
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

		private function dispatchHeightChange() : void {
			
			if (_currentHeight!=nHeight) {
				dispatchEvent(new IntrospectionNodeViewEvent(IntrospectionNodeViewEvent.HEIGHT_CHANGED, null, true));
				_currentHeight=nHeight;
			}
		}
		
		public function get a_doINWs() : Array {
			return _a_doINWs;
		}
		
		public function get oIntrospectionNode() : IntrospectionNode {
			return _introspectionNode;
		}
		
		public function get isSearchHit() : Boolean {
			return _isSearchHit;
		}
		
		public function get isHidden() : Boolean {
			return _isHidden;
		}
		
		public function get introspectionNode() : IntrospectionNode {
			return _introspectionNode;
		}
		
		public function set isHidden(isHidden : Boolean) : void {
			_isHidden = isHidden;
		}
	}
}
